/* eslint-disable @typescript-eslint/no-explicit-any */
import { transform } from "@babel/standalone";
import mainCode from "../template/main?raw";
import {
  getModuleFile,
  cssToJs,
  jsonToJs,
  beforeTransformCodeHandler,
} from "../utils";

import { COMPILER_FILE_ENUM, POST_MESSAGE_TYPE } from "../enum";
import { IFile, IFiles } from "../typings";

/**
 * 编译代码
 * @param file 当前需要编译的文件模块
 * @param files 总文件模块 也就是现在编辑器正在编辑的模块
 * @returns code 编译后的代码
 */
const babelTransform = (file: IFile, files: IFiles) => {
  try {
    const _code = beforeTransformCodeHandler(file.name, file.value);
    const babelFileResult = transform(_code, {
      sourceType: "module", // 资源类型 es模块支持
      presets: ["react", "typescript"], // 预设语言为react和ts
      filename: file.name,
      plugins: [
        // 自定义插件
        {
          visitor: {
            //自定义import语句
            ImportDeclaration: (path: any) => {
              // 获取当前import语句引入的name
              const moduleName: string = path.node.source.value;
              // 判断当前引入的是否是本地文件（以.开头的需要转换为本地资源在进行引入）不是本地资源则无需转换
              const isNative = moduleName.startsWith(".");
              if (!isNative) return;
              // 获取当前文件系统内的模块文件 没有创建此文件则不进行转换
              const module = getModuleFile(files, moduleName);
              if (!module) return;
              // 根据当前module的类型进行转换
              switch (module.type) {
                case "css":
                  path.node.source.value = cssToJs(module);
                  break;
                case "json":
                  path.node.source.value = jsonToJs(module);
                  break;
                default:
                  // 如果不是css和json类型说明引入的是组件 则需要对组件的文件进行编译并且转换为本地资源
                  path.node.source.value = URL.createObjectURL(
                    new Blob([babelTransform(module, files)!], {
                      type: "application/javascript",
                    })
                  );
                  break;
              }
            },
          },
        },
      ],
    });
    return babelFileResult.code;
  } catch (error) {
    postMessage({ type: POST_MESSAGE_TYPE.ERROR, data: error });
  }
};

// 接收外部消息
onmessage = async (event) => {
  const { data } = event as {
    data: IFiles;
  };
  try {
    // 获取入口文件的代码
    const enterFile = {
      name: COMPILER_FILE_ENUM.ENTRY_FILE_NAME,
      value: mainCode,
    } as IFile;
    // 从入口文件开始编译
    const compileCode = babelTransform(enterFile, data);
    const messageParams = {
      type: POST_MESSAGE_TYPE.UPDATE,
      data: {
        compileCode,
        importmap: data?.[COMPILER_FILE_ENUM.IMPORT_MAP_FILE_NAME]?.value,
      },
    };
    // 向外部发送消息
    postMessage(messageParams);
  } catch (e) {
    postMessage({ type: POST_MESSAGE_TYPE.ERROR, data: e });
  }
};
